#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <Includes.h>
#include <main.h>
#include <OPP_Debug.h>
#include <ringbuffer.h>
//#include <SVS_Mqtt.h>
#include <DRV_EC600S.h>
#include <DRV_EC600S_Sock.h>
#include <EC600S_AT/AT.h>
#include <EC600S_AT/AT_Urc.h>

//宏定义
#define MIN(a,b) ((a) < (b) ? (a) : (b))
//IO向量数据转换到STR
#define IOV2STR(iov,iovcnt,str) \
    if (iovcnt == 2)\
    {\
        memcpy(str, iov[0].iov_base, iov[0].iov_len);\
        memcpy(str + iov[0].iov_len, iov[1].iov_base, iov[1].iov_len);\
    }\
    else\
    {\
        memcpy(str, iov[0].iov_base, iov[0].iov_len);\
    }\
    str[s] = '\0';


//外部变量定义
extern t_debug_info module_list[];

//内部变量定义
static T_MUTEX  rbmux;
static struct ringbuffer rb;  //环形缓存索引
static char buf[2*460];  //环形缓存BUF,交流桩最大报文200字节+"\r\n+QIURC:xxx\r\n"+预留

//内部函数声明
int Ec600sRBAtReadResult2IOV (int * read_result, struct ringbuffer* rb, struct iovec iov[2]);
int Ec600sRBAtProc (const struct iovec iov[2], int iovcnt);

/**
@brief 二进制数据调试函数，减少对栈空间占用
@param
	-data    数据
    -len     长度
@return
**/
int DataDump(int module, char *tag, U8 *data, U16 len)
{
    int i=0;

    if(module_list[module].enable!=1)
        return 0;

    printf("\r\n%s data dump len=%d content:\r\n",tag,len);
    for(i=0;i<len;i++)
    {
        printf("%02x ",data[i]);
        if((i+1)%16==0)
        {
            printf("\r\n");

        }
    }
    printf("\r\n");
    return 0;
}

/**
@brief 字符数据调试函数，减少对栈空间占用
@param
	-data    数据
    -len     长度
@return
**/
int StringDump(int module, char *tag, char *str, U16 len)
{
    if(module_list[module].enable!=1)
        return 0;

    /*printf("\r\n>>>>>>>>>>>>>>>>>>len=%d,%s=",len,tag);
    for(int i=0;i<len;i++)
    {
        printf("%c",str[i]);
    }
    printf("<<<<<<<<<<<<<<<<<<<<<\r\n");*/
    printf("\r\n>>>>len=%d,%s=%s<<<<\r\n",len,tag,str);
    return 0;
}

/**
@brief rb主loop
@retval
*/
void RBLoop()
{
    static int read_result=0;//0.重新匹配开始符\r\n 1.继续当前查找报文.报文不完整需要继续查找read_result=1
    struct iovec iov [2];
    int iovcnt;

    MUTEX_LOCK(rbmux,MUTEX_WAIT_ALWAYS);
    if((iovcnt = Ec600sRBAtReadResult2IOV (&read_result, &rb, iov)) > 0)
    {
        //更新索引
        rb_read_upd (&rb, iov[0].iov_len + iov[1].iov_len);
        Ec600sRBAtProc(iov, iovcnt);
    }
    MUTEX_UNLOCK(rbmux);
}

/**
@brief ringbuffer任务，为了命令的快速响应单独创建任务
@param pvParameters 参数
@retval
*/
void rbTask(void *pvParameters)
{
    while(1){
        RBLoop();        
        WDG_Feed(*(int *)pvParameters);
        vTaskDelay(10 / portTICK_PERIOD_MS);
    }
}

/**
@brief ringbuffer 初始化
@retval 0成功
*/
int Ec600sRBInit()
{
	MUTEX_CREATE(rbmux);
	rb_init(&rb,buf,sizeof(buf));
    //创建任务提供命令响应及时性
    //BaseType_t res = xTaskCreate(rbTask, "rbTask", 128, NULL, 5, NULL);
    //if(res != pdPASS){
    //    printf("create rbTask err\r\n");
    //}
    return 0;
}

/**
@brief 向ringbuffer写数据
@param buf 数据
@param len 数据长度
@retval
*/
int Ec600sRBWrite(const char* buf, size_t len)
{
    int rlen;

    MUTEX_LOCK(rbmux,MUTEX_WAIT_ALWAYS);
    rlen=rb_write(&rb,buf,len);
    if(rlen==0)
    {
        DEBUG_LOG(DEBUG_MODULE_RB, DLL_ERROR, "rb full drop\r\n",rlen);
    }
    MUTEX_UNLOCK(rbmux);

    return rlen;
}

/**
@brief 从ringbuffer中读数据赋值给IO向量
@param read_result 读结果，0.没匹配到格式头,1.匹配到格式头
@param rb ringbuffer
@param iovec IO向量数据
@retval 赋值到IO向量数据长度
*/
int Ec600sRBAtReadResult2IOV (int * read_result, struct ringbuffer* rb, struct iovec iov[2])
{
	int	iovcnt = 0;
	int	res;
	size_t	s;
    char *str;
    int len;
    char *ptr;

	s = rb_used (rb);
	if (s > 0)
	{
        //printf("\r\nd_read_result %d len %d input [%.*s]\r\n", *read_result, s, MIN(s, rb->size - rb->read), (char*)rb->buffer + rb->read);


		if (*read_result == 0)
		{
			res = rb_memcmp (rb, "\r\n", 2);
			if (res == 0)
			{
				rb_read_upd (rb, 2);
				*read_result = 1;

				return 0;
			}
			else if (res > 0)
			{
				if (rb_memcmp (rb, "\n", 1) == 0)
				{
					//ast_debug (5, "[%s] multiline response\n", dev);
					rb_read_upd (rb, 1);

					return 0;
				}

				if (rb_read_until_char_iov (rb, iov, '\r') > 0)
				{
					s = iov[0].iov_len + iov[1].iov_len + 1;
				}

				rb_read_upd (rb, s);

				return 0;
			}

			return 0;
		}
		else
		{
			if (rb_memcmp (rb, "+QIURC:", 7) == 0)
			{
				iovcnt = rb_read_until_mem_iov (rb, iov, "\r\n", 2);
				*read_result = 0;
                s = iov[0].iov_len + iov[1].iov_len;
                if(s>0)
                {
                    str=(char *)malloc(s+1);
                    if(str==NULL)
                    {
                        DEBUG_LOG(DEBUG_MODULE_RB, DLL_ERROR, "memory leak\r\n");
                        return -1;
                    }
                    IOV2STR(iov,iovcnt,str);
                }
                else
                {
                    return -2;
                }
				res=sscanf(str,"%*[^,],%*[^,],%d%*[^\r\n]",&len);
                if(res!=1)
                {
                    free(str);
                    return -3;
                }
				s=s+len+3;//格式长度补齐\r\ndata\r 返回数据以\r结尾
                free(str);
                res=rb_read_n_iov (rb, iov, s);
                //数据不完整继续查找+QIURC:关键字
                if(res==0)
                {
                    *read_result = 1;
                    return -4;
                }
				return res;
			}
			else if (rb_memcmp (rb, "+QMTRECV:", 9) == 0)
			{
                //重新匹配开始符\r\n
                *read_result = 0;
                //先读出所有数据进行格式匹配
                iovcnt=rb_read_all_iov (rb, iov);
                s=iov[0].iov_len + iov[1].iov_len;
                if(s>0)
                {
                    str=(char *)malloc(s+1);
                    if(str==NULL)
                    {
                        DEBUG_LOG(DEBUG_MODULE_RB, DLL_ERROR, "memory leak\r\n");
                        return -1;
                    }
                    IOV2STR(iov,iovcnt,str);
                }
                else
                {
                    return -2;
                }

                //找第4个逗号赋值结束符
                if(0==strloc(str,",",4,&ptr))
                {
                    *ptr='\0';
                }
				res=sscanf(str,"%*[^:]:%*[^,],%*[^,],\"%*[^\"]\",%d",&len);
                if(res!=1)
                {
                    free(str);
                    return -3;
                }
				s=strlen(str)+len+1+2+1;//格式长度补齐\r\ndata\r 返回数据以\r结尾.1(,)+2("")+1(\r)
                free(str);
                res=rb_read_n_iov (rb, iov, s);
                //数据不完整继续查找+QMTRECV:关键字
                if(res==0)
                {
                    *read_result = 1;
                    return -4;
                }
				return res;
            }
            else
			{
				iovcnt = rb_read_until_mem_iov (rb, iov, "\r\n", 2);
				if (iovcnt > 0)
				{
					*read_result = 0;
					s = iov[0].iov_len + iov[1].iov_len + 1;//返回数据以\r结尾

					return rb_read_n_iov (rb, iov, s);
				}
			}
		}
	}

	return 0;
}

/*!
 * \brief Do process
 * \param iov -- elements array
 * \param iovcnt -- number of elements array
 * \retval  0 success
 * \retval -1 error
 */

int Ec600sRBAtProc (const struct iovec iov[2], int iovcnt)
{
	char*		str;
	size_t		len;
    char*       ptr,*ptr1;
    int         ret;

	if(iov[0].iov_len + iov[1].iov_len > 0)
	{
        //IOV不以\r\n开头，以\r结尾.
		len = iov[0].iov_len + iov[1].iov_len - 1;//IOV结尾剔除\r字符

        str=(char *)malloc(len + 1);//预留字符结尾符\0空间
        if(str==NULL)
        {
            DEBUG_LOG(DEBUG_MODULE_RB, DLL_ERROR, "memory leak\r\n");
            return -1;
        }
		if (iovcnt == 2)
		{
			memcpy(str, iov[0].iov_base, iov[0].iov_len);
			memcpy(str + iov[0].iov_len, iov[1].iov_base, iov[1].iov_len);
		}
		else
		{
            memcpy(str, iov[0].iov_base, iov[0].iov_len);
		}
		str[len] = '\0';

        //二进制数据不打印,由应用自己处理
        if(NULL==strstr(str,"+QIURC:"))
        {
            StringDump(DEBUG_MODULE_RB,"IOVSTR",str,len);
        }
        ptr=strstr(str,"+QIURC:");
        if(ptr!=NULL)
        {
            char tmp[64]={0};
            int sock,length;
            U8 *data;

            ret=sscanf(ptr,"%*[^,],%[^\r\n]",tmp);
            if(ret==1)
            {
                int count=strcount(tmp,",");
                //recv缓存模式
                if(count==0)
                {
                    ret=sscanf(tmp,"%d",&sock);
                    if(ret==1)
                    {
                        Ec600sSockHasDataSet(sock,1);
                    }
                }
                //recv直吐模式
                else if(count==1)
                {
                    ret=sscanf(tmp,"%d,%d",&sock,&length);
                    if(ret==2)
                    {
                        //查找数据开始标志位\r\n
                        ptr1 = strstr(ptr,"\r\n");
                        if(ptr1)
                        {
                            //拷贝数据
                            data=(U8 *)(ptr1+2);//跳过\r\n字符
                            DataDump(DEBUG_MODULE_RB, "QIURC", data, length);
                            Ec600sSockUrcCallback(sock,data,length);
                        }
                    }
                }
            }
        }
        //mqtt noted by wangtao
        /*ptr=strstr(str,"+QMTRECV:");
        if(ptr!=NULL)
        {
            ST_MQTT_RCV_EVENT_PARA *para;//使用动态分配减少栈资源占用
            para=(ST_MQTT_RCV_EVENT_PARA *)malloc(sizeof(ST_MQTT_RCV_EVENT_PARA));
            if(para==NULL)
            {
                goto EXIT;
            }
            memset(para,0,sizeof(ST_MQTT_RCV_EVENT_PARA));
            ret=sscanf(ptr,"%*[^:]:%d,%hd,\"%[^\"]\",%d%*[^,]",&para->client_idx,&para->msgid,para->topic,&para->payload_len);
            if(ret==4)
            {
                if(0==strloc(ptr,"\"",3,&ptr1))
                {
                    if(strlen(ptr1)-2==para->payload_len)
                    {
                        memcpy(para->payload,ptr1+1,para->payload_len);
                        para->payload[para->payload_len]='\0';
                        MqttCB(EVENT_MQTT_RECV, para);
                    }
                }
            }
            free(para);
        }
EXIT:*/
        free(str);
        str=NULL;
	}
	return 0;
}

